//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008-2010, Shane J. M. Liesegang
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright 
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the copyright holder nor the names of any 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "MathUtil.h"

///Simplifies lerping Actor properties across a timeframe
/** 
 * This is a helper template class that manages Actor properties during 
 *  lerp transitions. The following functions show how they are setup, and
 *  the Actor::Update function shows how to update and get the next values. 
 * 
 * @see Actor::MoveTo
 * @see Actor::RotateTo
 * @see Actor::ChangeColorTo
 * @see Actor::ChangeSizeTo
 * 
 * You can use Intervals for ints, floats, and any class that has defined 
 *  subtraction and division (by a float) operators that return members of 
 *  that same class. Our Color, Vector2, and Vector3 classes are all able
 *  to be used in Intervals. 
 */
template<class T>
class Interval
{
public:
	/**
	 * Setting up the inverval requires a starting value, a target ending state,
	 * and hoow long it should take to get there
	 *
	 * @param start the starting value
	 * @param end The ending value
	 * @param duration Length of the transition in seconds
	 */
	Interval(T start, T end, float duration, bool smooth = false) :
	  _start(start),
	  _end(end),
	  _current(start),
	  _duration(duration),
	  _timer(0.0f),
	  _shouldStep(true),
	  _smoothStep(smooth)
	  {
	  }

	  /**
	   * The default constructor just sets up an Interval that does nothing. It's
	   * here because some compilers want it.
	   */
	  Interval()
	  {
		  _shouldStep = false;
	  }

	  /**
	   * the step function processes the appropriate change and shuts the interval
	   * down if it's finished.
	   *
	   * @param dt How munch time has elapsed since the last Step (so how munch
	   * the Interval should be incremented)
	   * @return The current value of the Interval after the Step has been completed.
	   */
	  T Step(float dt)
	  {
		  if(!_shouldStep)
			  return _current;

		  _timer += dt;

		  if (_timer >= _duration)
		  {
			  _current = _end;
			  _shouldStep = false;
		  }
		  else
		  {
			  float stepRatio = _timer / _duration;
			  if (_smoothStep)
			  {
				  // smooth step
				  _current = MathUtil::SmoothStep(_start, _end, stepRatio);
			  }
			  else
			  {
				  // simple lerp
				  _current = MathUtil::Lerp(_start, _end, stepRatio);
			  }
		  }
		  return _current;
	  }

	  /**
	   * Get the current value without Stepping the Interval
	   *
	   * @return The current value
	   */
	  float GetCurrent()
	  {
		  return _current;
	  }

	  /**
	   * Whether or not the Interval still has changes to process. If this
	   * returns false, the Interval is done and you can disgard it.
	   *
	   * @return
	   */
	  bool ShouldStep()
	  {
		  return _shouldStep;
	  }

private:
	T _start;
	T _end;
	T _current;

	float _duration;
	float _timer;

	bool _shouldStep;
	bool _smoothStep;
};